# -*- encoding: utf-8 -*-
from openerp.osv import fields,osv
import openerp.addons.decimal_precision as dp
from openerp.tools.float_utils import float_compare
from datetime import datetime

class stock_location(osv.osv):
    _inherit = 'stock.location'
    _columns={'auto_trans_loc_ids':fields.many2many('stock.location','loc_auto_tran_rel','loc_target_id','loc_source_id',
                                                        string='自动移库locations',help='出库库存不够自动补货的location ids'),
                'property_auto_trans_account_id_out': fields.property(
                    'account.account',
                    type='many2one',
                    relation='account.account',
                    string="转出库位出库费用科目",
                    view_load=True,
                    help="auto_trans_loc_ids自动转出需要记录的费用科目"),  
                'property_auto_trans_account_id_in': fields.property(
                    'account.account',
                    type='many2one',
                    relation='account.account',
                    string="转入库位出库费用科目",
                    view_load=True,
                    help="自动转入到当前库位需要记录的费用科目"),
              }
    #来自dmp_stock_partial_pick, 检查出库单可用数量的方法
    def _product_out_avail(self, cr, uid, ids, product_id, product_qty, context=None, lock=False):
        #检查可用数量的时候, 增加相关自动移库的location
        for loc in self.browse(cr, uid, ids, context=context):
            if loc.auto_trans_loc_ids:
                ids += [loc_auto_trans.id for loc_auto_trans in loc.auto_trans_loc_ids if loc_auto_trans.id not in ids]
        return super(stock_location, self)._product_out_avail(cr, uid, ids, product_id, product_qty, context=context, lock=lock)

from openerp.addons.dmp_stock_partial_pick.stock_partial_picking import stock_partial_picking as stock_partial_picking_dmp
def _partial_move_for_multi_loc(self, cr, uid, move, context=None):
    partial_move = super(stock_partial_picking_dmp, self)._partial_move_for(cr, uid, move)
    #for the internal/out picking, need control the available out quantity        
    if move.picking_id.type in('internal', 'out'):
#            quantity = min(partial_move['quantity'], move.quantity_out_available)
#            partial_move.update({'quantity': quantity,'quantity_out_available':move.quantity_out_available})
#        qty_onhand = self.pool.get('product.product')._product_available(cr,uid,[move.product_id.id],['qty_onhand'],context={'location':move.location_id.id})
#        quantity_out_available = qty_onhand[move.product_id.id]['qty_onhand'] 
        #johnw, 2016/07/31, 使用qty_ohhand_multi_loc作为数量进行检查
        qty_onhand = self.pool.get('product.product').read(cr, uid, move.product_id.id, ['qty_ohhand_multi_loc'], context={'location':move.location_id.id})
        quantity_out_available = qty_onhand['qty_ohhand_multi_loc']  
        quantity_out_available = self.pool.get('product.uom')._compute_qty(cr, uid, move.product_id.uom_id.id, quantity_out_available, partial_move['product_uom'])  
        quantity = min(partial_move['quantity'], quantity_out_available)
        partial_move.update({'quantity': quantity,'quantity_out_available':quantity_out_available})                  
        
    #the max quantity that user can deliver and the picking type
    partial_move.update({'quantity_max':move.product_qty, 'pick_type':move.picking_id.type, 'state':move.state})
    return partial_move   

stock_partial_picking_dmp._partial_move_for = _partial_move_for_multi_loc

class stock_partial_picking(osv.osv_memory):
    _inherit = "stock.partial.picking"
    def do_partial(self, cr, uid, ids, context=None):
        def _get_pick_vals():
            pick_key = '%s-%s-%s'%(partner_id, location_id, location_dest_id)
            pick_vals = auto_tran_picks.get(pick_key, False)
            if not auto_tran_picks.get(pick_key):
                pick_vals = self.pool.get('stock.picking').onchange_partner_in(cr, uid, [], partner_id=partner_id, context=context)['value']
                pick_vals.update({
                                    'name': pick_name,
                                    'partner_id':partner_id,
                                    'type': pick_type,
                                    'date': datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'),
                                    'state': 'done',
                                    'invoice_state': '2binvoiced',
                                    'origin': '%s:%s'%(wizard_line.move_id.picking_id.origin or '', wizard_line.move_id.picking_id.name),
                                     'location_id':location_id,
                                     'location_dest_id':location_dest_id,
                                     'move_lines':[],
                                    'company_id': company_id,})                                
                auto_tran_picks[pick_key] = pick_vals       
            return pick_vals   
        def _add_move_vals(move_lines):
            move_lines.append((0,0,{
                                    'date': datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'),
                                    'location_id': location_id,
                                    'location_dest_id': location_dest_id,
                                    'state': 'done',
                                    'name': wizard_line.product_id.default_code,
                                    'product_id': wizard_line.product_id.id,
                                    'product_qty': move_qty,
                                    'product_uos_qty': move_qty,
                                    'product_uom': wizard_line.product_uom.id,
                                    'product_uos': wizard_line.product_uom.id,
                                    'date_expected': fields.date.context_today(self, cr, uid, context=context),  
                                    'company_id': company_id,   
                                    }))               
            
        partial = self.browse(cr, uid, ids[0], context=context)
        picking_type = partial.picking_id.type
        prod_obj = self.pool.get('product.product')
        move_obj = self.pool.get('stock.move')
        uom_obj = self.pool.get('product.uom')
        auto_tran_picks = {}
        for wizard_line in partial.move_ids:
            if picking_type in('internal', 'out'):
                '''
                                下面代码基于dmp_stock_partial_pick相关代码修改
                '''
                #get onhand quantity as out available quantity
                c = context.copy()
                c['location'] = wizard_line.location_id.id
                prod_id = wizard_line.product_id.id
                qty_onhand = prod_obj.read(cr,uid,prod_id,['qty_available','qty_ohhand_multi_loc'],context=c)
                #johnw, 2014/07/31, 使用qty_ohhand_multi_loc作为可用库存进行检查
                quantity_out_available_loc = qty_onhand['qty_available']
                quantity_out_available_multi_loc = qty_onhand['qty_ohhand_multi_loc']
                #基本单位与销售单位进行转换
                partial_qty = wizard_line.quantity
                if wizard_line.product_uom != wizard_line.product_id.uom_id:
                    partial_qty = uom_obj._compute_qty_obj(cr, uid, wizard_line.product_uom, wizard_line.quantity, wizard_line.product_id.uom_id)
                precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Product Unit of Measure')
                if float_compare(partial_qty , quantity_out_available_multi_loc, precision_digits=precision) <= 0 \
                    and float_compare(partial_qty , quantity_out_available_loc, precision_digits=precision) == 1:
                    if not wizard_line.location_id.company_id:
                        raise osv.except_osv('错误','自动移库的库位[%s]必须设置公司'%(wizard_line.location_id.complete_name))  
                    #准备自动转移数据
                    qty_miss = partial_qty - quantity_out_available_loc
                    res_model,loc_customer_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_customers')
                    res_model,loc_supplier_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_suppliers')
                    for loc in wizard_line.location_id.auto_trans_loc_ids:
                        if qty_miss <= 0:
                            break
                        if not loc.company_id:
                            raise osv.except_osv('错误','自动移库的库位[%s]必须设置公司'%(wizard_line.location_id.complete_name))  
                        if loc.company_id.id != wizard_line.location_id.company_id:
                            #公司之间移动, 需创建出库单和入库单
                            qty_onhand_loc = prod_obj.read(cr,uid,prod_id,['qty_available'],context={'location':loc.id})['qty_available']
                            move_qty = qty_onhand_loc >= qty_miss and qty_miss or qty_onhand_loc
                            qty_miss -= move_qty
                            
                            #1.源库位出库到目标公司, partner为目标公司partner
                            pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.out')
                            pick_type = 'out'
                            partner_id = wizard_line.location_id.company_id.partner_id.id
                            company_id = loc.company_id.id
                            location_id = loc.id
                            location_dest_id = loc_customer_id
                            #初始化pick数据
                            pick_vals = _get_pick_vals()
                            #添加move行
                            _add_move_vals(pick_vals.get('move_lines'))   
                                                    
                            #2.现库位从员库位的公司入库
                            pick_name = self.pool.get('ir.sequence').get(cr, uid, 'stock.picking.in')
                            pick_type = 'in'
                            partner_id = loc.company_id.partner_id.id
                            company_id = wizard_line.location_id.company_id.id
                            location_id = loc_supplier_id
                            location_dest_id = wizard_line.location_id.id
                            #初始化pick数据
                            pick_vals = _get_pick_vals()
                            #添加move行
                            _add_move_vals(pick_vals.get('move_lines'))  
                        else:
                            #一个公司, 直接进行移库, 北川目前不处理
                            pass
        if auto_tran_picks:
            #创建相关picking
            pick_ids = []
            for value in auto_tran_picks.values():
                #前面values里面的state直接设置为done,无需运行工作流
                pick_id = self.pool.get('stock.picking').create(cr, uid, value, context=context)
                pick_ids.append(pick_id)
            move_ids = self.pool.get('stock.move').search(cr, uid, [('picking_id','in',pick_ids)], context=context)
            self.pool.get('stock.move').action_done(cr, uid, move_ids, context=context)
        return super(stock_partial_picking,self).do_partial(cr, uid, ids, context=context)    
    
class product_product(osv.osv):
    _inherit = 'product.product'
    def _product_available_multi_stock(self, cr, uid, ids, field_names=None, arg=False, context=None):
        """ Finds the incoming and outgoing quantity of product.
        @return: Dictionary of values
        """
        if not field_names:
            field_names = []
        if context is None:
            context = {}
        res = {}
        for id in ids:
            res[id] = {}.fromkeys(field_names, 0.0)
        for f in field_names:
            c = context.copy()
            '''
                        处理multi location, 设置context里面的location为处理过的location
            '''
            if f == 'qty_ohhand_multi_loc':
                c.update({ 'states': ('done',), 'what': ('in', 'out') })
            if f == 'qty_virtual_multi_loc':
                #c.update({ 'states': ('confirmed','waiting','assigned','done'), 'what': ('in', 'out') })
                #johnw, 2016/06/14, add qc states for the incoming/outgoing/virtual
                c.update({ 'states': ('confirmed','waiting','assigned','done','qc','quality'), 'what': ('in', 'out') })      
            stock = self.get_product_available(cr, uid, ids, context=c)
            for id in ids:
                res[id][f] = stock.get(id, 0.0)
            #处理关联的location
            location_ids = self._get_locations_from_context(cr, uid, ids, context=context)
            location_ids_new = []
            for loc in self.pool.get('stock.location').browse(cr, uid, location_ids, context=context):
                if loc.auto_trans_loc_ids:
                    location_ids_new += [loc_auto_trans.id for loc_auto_trans in loc.auto_trans_loc_ids if loc_auto_trans.id not in location_ids]
            if location_ids_new:
                location_ids_new = list(set(location_ids_new))     
                c_new = c.copy()
                c_new['location'] = location_ids_new
                stock = self.get_product_available(cr, uid, ids, context=c_new)
                for id in ids:
                    res[id][f] += stock.get(id, 0.0)
                            
        return res    
    _columns = {
        'qty_ohhand_multi_loc': fields.function(_product_available_multi_stock, multi='qty_multi_loc',
            type='float',  digits_compute=dp.get_precision('Product Unit of Measure'),
            string='考虑相关auto_trans_loc_ids的onhand',
             ),
        'qty_virtual_multi_loc': fields.function(_product_available_multi_stock, multi='qty_multi_loc',
            type='float',  digits_compute=dp.get_precision('Product Unit of Measure'),
            string='考虑相关auto_trans_loc_ids的forecast',
             ),
    }  
    
#检查订购点的预测数量的获取    
from openerp.addons.procurement.schedulers import procurement_order as procurement_order_op
                
def _product_virtual_get_multi_loc(self, cr, uid, order_point):
    order_point.location_id
    location_obj = self.pool.get('stock.location')
    qty = location_obj._product_virtual_get(cr, uid,
            order_point.location_id.id, [order_point.product_id.id],
            {'uom': order_point.product_uom.id})[order_point.product_id.id]
    #增加相关location数量
    if order_point.location_id.auto_trans_loc_ids:
        for loc in order_point.location_id.auto_trans_loc_ids:
            qty += location_obj._product_virtual_get(cr, uid,
                loc.id, [order_point.product_id.id],
                {'uom': order_point.product_uom.id})[order_point.product_id.id]
    return qty

procurement_order_op._product_virtual_get = _product_virtual_get_multi_loc

#按订单检查库存参数
class procurement_order(osv.osv):
    _inherit = 'procurement.order'
    
    def _prod_inv_info(self, cr, uid, prod, location, uom, context=None):
        inv_info = super(procurement_order, self)._prod_inv_info(cr, uid, prod, location, uom, context)
        if location.auto_trans_loc_ids:
            for loc_auto_tran in location.auto_trans_loc_ids:
                inv_info += "\n" + super(procurement_order, self)._prod_inv_info(cr, uid, prod, loc_auto_tran, uom, context)
        return inv_info
    
    def _mto_check_inv_qty_avail(self, cr, uid, proc, context=None):
        qty = self.pool.get('product.product').read(cr, uid, proc.product_id.id, 
                                                  #['qty_virtual_multi_loc','qty_virtual','virtual_available'], 
                                                  ['qty_virtual_multi_loc'],
                                                  context={'location':proc.location_id.id,'active_test':False})
        qty_avail = qty['qty_virtual_multi_loc']
        return qty_avail
    
    def _prod_qty_forecast_field_name(self, cr, uid, ids, context=None):
        return 'qty_virtual_multi_loc'